package baks

import (
	"database/sql"
	"errors"
	"fmt"
	"log"
	"regexp"
	"strings"
	"sync"
	"time"

	"gitee.com/zibianqu/fyzdb/connection"
	"gitee.com/zibianqu/fyzdb/connection/mysql"
	"gitee.com/zibianqu/fyzdb/lib"
	"gitee.com/zibianqu/fyzdb/lib/mts"
	"gitee.com/zibianqu/fyzdb/lib/rand"
	"gitee.com/zibianqu/fyzdb/lib/str"
	"gitee.com/zibianqu/fyzdb/lib/variable"
	"github.com/spf13/cast"
)

var mapping = "fcl"

// 会话对象
type SessionObj struct {
	SessionId  int64
	StartTime  int64
	Connection string
	Tx         *sql.Tx
	Builder    *Builder
}

var sessionMutex sync.RWMutex

// 会话列表
var SessionList = make(map[int64]*SessionObj)

// 获取会话
func Session(sessionIds ...int64) *SessionObj {
	defer CleanSession()

	sessionId := int64(0)
	tempSeesionList := GetSessionList()
	for _, sessionId = range sessionIds {
		if session, ok := tempSeesionList[sessionId]; ok {
			return session
		}
	}
	sessionId = lib.UniqueId()
	s := &SessionObj{
		SessionId:  sessionId,
		Connection: "default",
		// 保证在使用的时候都是新的构建器
		Builder:   MakeBuilder(sessionId),
		StartTime: time.Now().Unix(),
	}
	sessionMutex.Lock()
	SessionList[sessionId] = s
	sessionMutex.Unlock()
	return s
}

// 获取sessionList
func GetSessionList() map[int64]*SessionObj {
	sessionMutex.RLock()
	tempSeesionList := make(map[int64]*SessionObj)
	for sid, sl := range SessionList {
		tempSeesionList[sid] = sl
	}
	sessionMutex.RUnlock()
	return tempSeesionList
}

func CleanSession() {
	// 并发情况下读写跟迭代同时进行会报错
	// 先获取，然后在去操作
	tempSeesionList := GetSessionList()
	for sid, v := range tempSeesionList {
		if v.StartTime+int64(time.Second)*60*60 > time.Now().Unix() {
			// 超过1一小时就清除
			continue
		}
		DelSession(sid)
	}
}

func DelSession(sid int64) {
	sessionMutex.Lock()
	defer sessionMutex.Unlock()
	delete(SessionList, sid)
}

func MakeBuilder(sessionId int64) *Builder {
	return &Builder{
		SessionId:  sessionId,
		connection: "",
		logSql:     "",
		log:        false,
		mapping:    mapping,
	}
}

func (s *SessionObj) SetConnection(connection string) *SessionObj {
	s.Connection = connection
	s.Builder.connection = connection
	return s
}

func (s *SessionObj) GetSessionId() int64 {
	return s.SessionId
}

func (s *SessionObj) BeginTrans(connection ...string) *SessionObj {
	for _, s.Connection = range connection {
	}
	db := mysql.Mysql().GetDb(s.Connection)
	tx, err := db.Begin()
	lib.ThrowError(err)
	// fmt.Println("开启事务", s.SessionId, tx)
	s.Tx = tx
	return s
}

func (s *SessionObj) Commit() error {
	err := s.Tx.Commit()
	s.Tx = nil
	DelSession(s.SessionId)
	return err
}

func (s *SessionObj) Rollback() error {
	err := s.Tx.Rollback()
	s.Tx = nil
	DelSession(s.SessionId)
	return err
}

type whereObj struct {
	field   string
	operate string
	value   string
	bind    bool
}

type Builder struct {
	SessionId  int64
	connection string
	// 字段映射
	mapping string
	// 事务
	field      []string
	table      []string
	join       []string
	where      []whereObj
	order      []string
	skip       int
	take       int
	limit      string
	group      []string
	having     string
	bindParams map[string]any
	sql        string
	logSql     string
	log        bool
}

func Table(table ...string) *Builder {
	var builder = Builder{
		connection: "",
		table:      table,
		logSql:     "",
		log:        false,
		mapping:    mapping,
	}
	return &builder
}

func Connection(conn string) *Builder {
	var builder = Builder{
		connection: conn,
		logSql:     "",
		log:        false,
		mapping:    mapping,
	}
	return &builder
}

func (b *Builder) GetSessionId() int64 {
	return b.SessionId
}

func (b *Builder) SetSessionId(sid int64) connection.IBuilder {
	b.SessionId = sid
	return b
}

func (b *Builder) Table(table ...string) connection.IBuilder {
	/*for _, t := range table {
		b.table = append(b.table, t)
	}*/
	var builder = &Builder{
		connection: b.connection,
		table:      table,
		logSql:     "",
		log:        false,
		mapping:    mapping,
	}
	return builder
}

func (b *Builder) getDb() *sql.DB {
	db := mysql.Mysql().GetDb(b.connection)
	return db
}

// @param table 表名 sys_user as a
// @param onWhere 条件
func (b *Builder) Join(table, onWhere string) connection.IBuilder {
	joinSql := fmt.Sprintf("inner join %s on %s", table, onWhere)
	b.join = append(b.join, joinSql)
	return b
}

// @param table 表名 sys_user as a
// @param onWhere 条件
func (b *Builder) LeftJoin(table, onWhere string) connection.IBuilder {
	joinSql := fmt.Sprintf("left join %s on %s", table, onWhere)
	b.join = append(b.join, joinSql)
	return b
}

// @param table 表名 sys_user as a
// @param onWhere 条件
func (b *Builder) RightJoin(table, onWhere string) connection.IBuilder {
	joinSql := fmt.Sprintf("right join %s on %s", table, onWhere)
	b.join = append(b.join, joinSql)
	return b
}

// @param field 第1个参数字段名称，可以'a.UserId'、'UserId'
// @param operate 第2个参数，可能为链接符，如=，> < 等;可能为条件值operate为`=`
// @param value 第3个参数，可能为是否绑定，也可能为条件的值
// @param isBind 4个参数，第四个参数为是否需要绑定参数
func (b *Builder) Where(params ...any) connection.IBuilder {
	length := len(params)
	if length < 1 {
		log.Fatal("params is error !")
	}
	field, operate, value, bind := "", "", "", true
	field = cast.ToString(params[0])
	if length == 1 {
		bind = false
	}
	if length > 1 {
		// 如果只有两个，说明operate为操作符’=‘
		operate = cast.ToString(params[1])
		if length == 2 {
			value = operate
			operate = "="
		}
	}
	if length > 2 {
		value = cast.ToString(params[2])
		// 如果第3参数为true、false则需要判断是否需要绑定参数
		isBind := params[2]
		isBindType := fmt.Sprintf("%T", isBind)
		if length == 3 && isBindType == "bool" {
			bind = isBind.(bool)
			value = operate
			operate = "="
		}
	}
	if length == 4 {
		// 上面已经获取
		/*operate = lib.Str.Conversion(params[1])
		value = lib.Str.Conversion(params[2])*/
		// 如果第4参数为true、false则需要判断是否需要绑定参数
		isBind := params[3]
		isBindType := fmt.Sprintf("%T", isBind)
		if length == 3 && isBindType == "bool" {
			bind = isBind.(bool)
			value = operate
			operate = "="
		}
	}
	b.where = append(b.where, whereObj{field: field, operate: operate, value: value, bind: bind})
	return b
}

// 排序
func (b *Builder) OrderBy(params ...string) connection.IBuilder {
	length := len(params)
	if length < 1 {
		log.Fatal("params is error !")
	}
	field, direct := "", ""
	field = params[0]
	if length == 2 {
		direct = params[1]
	}
	b.order = append(b.order, field+" "+direct)
	return b
}

func (b *Builder) Skip(offset int) connection.IBuilder {
	b.skip = offset
	return b
}

func (b *Builder) Take(limit int) connection.IBuilder {
	b.take = limit
	return b
}

func (b *Builder) Group(field string) connection.IBuilder {
	b.group = append(b.group, field)
	return b
}

func (b *Builder) Having(raw string) connection.IBuilder {
	b.having = raw
	return b
}

func (b *Builder) Select(fields ...string) connection.IBuilder {
	length := len(fields)
	if length < 1 {
		log.Fatal("params is error !")
	}
	for _, v := range fields {
		b.field = append(b.field, v)
	}
	return b
}

// 参数绑定
func (b *Builder) BindParam(bpToMap map[string]any) connection.IBuilder {
	if b.bindParams == nil {
		b.bindParams = make(map[string]any)
	}
	for k, v := range bpToMap {
		b.bindParams[k] = v
	}
	return b
}

// 日志开启
func (b *Builder) Log() connection.IBuilder {
	b.log = true
	return b
}

// 获取日志sql
func (b *Builder) GetLogSql() string {
	return b.logSql
}
func (b *Builder) Get(dest ...any) []map[string]any {
	sql, bindParam := b.assembleQuerySql()
	if b.log {
		b.logSql = sql
		return nil
	}
	result := b.Query(sql, bindParam)
	if result == nil {
		return result
	}
	length := len(dest)
	if length > 0 {
		// 赋值的结构体
		for _, v := range dest {
			// lib.Map0Struct(result, v)
			mts.Covert(result, v, b.mapping)
		}
	}
	return result
}

// @param dest 赋值目标结构体
func (b *Builder) First(dest ...any) map[string]any {
	b.Skip(0)
	b.Take(1)
	sql, bindParam := b.assembleQuerySql()
	if b.log {
		b.logSql = sql
		return nil
	}
	res := b.Query(sql, bindParam)
	if res == nil {
		return nil
	}
	result := res[0]
	length := len(dest)
	if length > 0 {
		// 赋值的结构体
		for _, v := range dest {
			// lib.Map0Struct(result, v)
			mts.Covert(result, v, b.mapping)
		}
	}
	return result
}

func (b *Builder) FetchAll(sql string, bindParam ...any) []map[string]any {
	result := b.Query(sql, bindParam)
	return result
}

func (b *Builder) FetchOne(sql string, bindParam ...any) map[string]any {
	aSql := strings.ToLower(sql)
	if !str.Obj().Contains(aSql, " limit ") {
		sql += " limit 1"
	}
	res := b.Query(sql, bindParam)
	if res == nil {
		return nil
	}
	result := res[0]
	return result
}

func (b *Builder) Count(fieldSql ...string) int64 {
	length := len(fieldSql)
	b.field = make([]string, 0)
	if length > 0 {
		fSql := fieldSql[0]
		b.field = append(b.field, "count("+fSql+") as Number")
	} else {
		b.field = append(b.field, "count(1) as Number")
	}
	sql, bindParam := b.assembleQuerySql()
	if b.log {
		b.logSql = sql
		return 0
	}
	res := b.Query(sql, bindParam)
	if res == nil {
		return 0
	}
	result := res[0]
	return result["Number"].(int64)
}

func (b *Builder) Sum(Column string) any {
	b.field = make([]string, 0)
	b.field = append(b.field, "sum("+Column+") as Number")
	sql, bindParam := b.assembleQuerySql()
	if b.log {
		b.logSql = sql
		return 0
	}
	res := b.Query(sql, bindParam)
	if res == nil {
		return 0
	}
	result := res[0]
	return result["Number"]
}

func (b *Builder) Value(column string) any {
	b.Skip(0)
	b.Take(1)
	b.field = make([]string, 0)
	b.field = append(b.field, column)
	sql, bindParam := b.assembleQuerySql()
	if b.log {
		b.logSql = sql
		return 0
	}
	res := b.Query(sql, bindParam)
	if res == nil {
		return 0
	}
	result := res[0]
	return result[column]
}

func (b *Builder) Pluck(column string) []any {
	b.field = make([]string, 0)
	b.field = append(b.field, column)
	sql, bindParam := b.assembleQuerySql()
	if b.log {
		b.logSql = sql
		return nil
	}
	res := b.Query(sql, bindParam)
	if res == nil {
		return nil
	}
	result := make([]any, 0)
	for _, val := range res {
		if v, ok := val[column]; ok {
			result = append(result, v)
		}
	}
	return result
}

// 获取字段的名称并且附上随机字符串，让他变唯一
func getRealField(field string) string {
	randStr := rand.String(6)
	// unid := lib.UniqueId()
	unid := rand.GetRandomWithAll(1000000, 9999999)
	if str.Obj().Contains(field, ".") {
		spArr := strings.Split(field, ".")
		f := spArr[1]
		return fmt.Sprintf("%s_%s_%d", f, randStr, unid)
	}
	return fmt.Sprintf("%s_%s_%d", field, randStr, unid)
}

// 正则获取字符串的字段
func regexBindField(sql string, bpToMap map[string]any) []string {
	re := regexp.MustCompile(":([\\w|\\d|_]*)")
	fieldArr := re.FindAllStringSubmatch(sql, -1)
	bindField := make([]string, 0)
	for _, v := range fieldArr {
		field := v[1]
		if variable.InKeyMap[string](field, bpToMap) {
			bindField = append(bindField, field)
		}
	}
	return bindField
}

// sql参数绑定
func sqlBindParam(b *Builder, sql string, bpToMap map[string]any) (string, []any) {
	bindField := regexBindField(sql, bpToMap)
	bpArr := make([]any, 0)
	for _, f := range bindField {
		if b.log {
			sql = strings.ReplaceAll(sql, ":"+f, cast.ToString(bpToMap[f]))
		} else {
			sql = strings.ReplaceAll(sql, ":"+f, "?")
		}
		bpArr = append(bpArr, bpToMap[f])
	}
	return sql, bpArr
}

// 查询语句组装
func (b *Builder) assembleQuerySql() (string, []any) {
	field, tables := "*", ""
	// 表字段
	if b.field != nil {
		field = strings.Join(b.field, ",")
	}
	// 表名
	if b.table == nil {
		lib.ThrowError(errors.New(" table is error !"))
	}
	tables = strings.Join(b.table, ",")
	sql := "select " + field + " from " + tables
	// 左右连接
	if len(b.join) > 0 {
		sql = fmt.Sprintf("%s %s", sql, strings.Join(b.join, " "))
	}
	// bindParams := make([]interface{}, 0)
	bpToMap := make(map[string]any)
	// 条件
	if b.where != nil {
		whereArr := make([]string, 0)
		for _, v := range b.where {
			wstr := v.field + " " + v.operate
			if !b.log && v.bind {
				/* wstr += " ?"
				bindParams = append(bindParams, v.value) */
				bindField := getRealField(v.field)
				wstr += " :" + bindField
				bpToMap[bindField] = v.value
			} else {
				if v.value != "" {
					wstr += " '" + v.value + "' "
				}

			}
			whereArr = append(whereArr, wstr)
		}
		sql += " where " + strings.Join(whereArr, " and ")
	}

	if b.group != nil {
		sql += " group by " + strings.Join(b.group, ",")
		if b.having != "" {
			sql += "  having " + b.having
		}
	}

	// 排序
	if b.order != nil {
		sql += " order by " + strings.Join(b.order, ",")
	}

	if b.take > 0 {
		//pageIndex := lib.Str.Conversion(lib.If(b.skip >= 1, (b.skip-1)*b.take, 0))
		pageIndex := cast.ToString(b.skip)
		sql += " limit " + pageIndex + " , " + cast.ToString(b.take)
	}
	b.BindParam(bpToMap)
	return sqlBindParam(b, sql, b.bindParams)
}

// @link http://www.360doc.com/content/22/0427/15/78746357_1028559956.shtml 事务
// p1: sql, p2: bindparam
func (b *Builder) Query(strs ...interface{}) []map[string]interface{} {
	length := len(strs)
	if length < 1 {
		log.Fatal("params is error !")
	}
	sqlStr := cast.ToString(strs[0])
	bindParams := make([]interface{}, 0)
	if length > 1 {
		bindParams = strs[1].([]interface{})
	}
	fields := make([]string, 0)
	fieldTypes := make([]*sql.ColumnType, 0)
	stmt := new(sql.Stmt)
	err := errors.New("")
	session := Session(b.SessionId)
	if session.Tx != nil {
		tx := session.Tx
		stmt, err = tx.Prepare(sqlStr)
		lib.ThrowError(err)
		defer stmt.Close()
	} else {
		db := mysql.Mysql().GetDb(b.connection)
		stmt, err = db.Prepare(sqlStr)
		lib.ThrowError(err)
		defer stmt.Close()
	}
	result, err := stmt.Query(bindParams...)
	lib.ThrowError(err)
	fields, err = result.Columns()
	lib.ThrowError(err)
	fieldTypes, err = result.ColumnTypes()
	lib.ThrowError(err)
	var rows []map[string]any
	defer result.Close()
	for result.Next() {
		acceptRow := make([]any, len(fields))
		row := make(map[string]any)
		for i := range acceptRow {
			acceptRow[i] = &acceptRow[i]
		}
		err = result.Scan(acceptRow...)
		lib.ThrowError(err)
		for i, v := range acceptRow {
			tp := fieldTypes[i].DatabaseTypeName()
			val, err := b.FieldReflect(fields[i], tp, v)
			lib.ThrowError(err)
			row[fields[i]] = val
		}
		rows = append(rows, row)
	}
	return rows
}

// 数据库字段映射
func (b *Builder) FieldReflect(field, tp string, v any) (value any, err error) {
	value = v
	// 先强转字符串，在转为对应类型
	//tmp := lib.Str.Conversion(v)
	_, isUint8 := v.([]uint8)
	if isUint8 {
		v = string(v.([]uint8))
	}
	// log.Println(field, tp, fmt.Sprintf("%T", v), v, isUint8)
	if variable.IsEmpty(v) {
		value = v
		return
	}
	switch tp {
	case "TINYINT", "SMALLINT", "INT", "INTEGER", "YEAR", "MEDIUMINT":
		value = cast.ToInt64(v)
		break
	case "BIGINT":
		value = cast.ToInt64(v)
		break
	case "DECIMAL":
		value = cast.ToFloat64(v)
		break
	case "FLOAT":
		value = cast.ToFloat64(v)
		break
	case "DOUBLE":
		value, _ = v.(float64)
		break
	case "VARCHAR", "CHAR", "TEXT", "JSON":
		value = cast.ToString(v)
		break
	case "DATETIME":
		if _, ok := v.(string); ok {
			value, err = time.ParseInLocation(lib.TimeFormat, v.(string), time.Local)
			break
		}
		value = v.(time.Time)
		break
	case "DATE":
		if _, ok := v.(string); ok {
			value, err = time.ParseInLocation(lib.DateFormat, v.(string), time.Local)
			break
		}
		value = v.(time.Time)
		break
	case "TIME", "TIMESTAMP":

		if _, ok := v.(string); ok {
			value, err = time.ParseInLocation(lib.TimeFormat, v.(string), time.Local)
			break
		}
		value = v.(time.Time)
		break
	default:
		fmt.Println(field + "【" + tp + "】 unknown or unSupport type in mysql")
		break
	}
	return
}

// 执行
func (b *Builder) Execute(sql string, bps ...any) (rowsAffect int64) {
	bpLen := len(bps)
	bpToMap := make(map[string]any)
	bindParams := make([]any, 0)
	if bpLen == 1 {
		if v, ok := bps[0].(map[string]any); ok {
			bpToMap = v
		} else {
			bindParams = bps
		}
	}
	if bpLen > 1 {
		bindParams = bps
	}
	if len(bpToMap) != 0 {
		sql, bindParams = sqlBindParam(b, sql, bpToMap)
	}
	session := Session(b.SessionId)
	if session.Tx != nil {
		tx := session.Tx
		result, err := tx.Exec(sql, bindParams...)
		lib.ThrowError(err)
		rowsAffect, err = result.RowsAffected()
		lib.ThrowError(err)
		return
	}
	db := b.getDb()
	stmt, err := db.Prepare(sql)
	lib.ThrowError(err)
	defer stmt.Close()
	result, err := stmt.Exec(bindParams...)
	lib.ThrowError(err)
	rowsAffect, err = result.RowsAffected()
	lib.ThrowError(err)
	return
}

func (b *Builder) Insert(save any) (rowsAffect int64, lastInsertId int64) {
	if b.table == nil {
		lib.ThrowError(errors.New(" table is error !"))
	}
	tables := strings.Join(b.table, ",")
	sql := "insert into " + tables + "("
	var tmp = make(map[string]any)
	// lib.Map0Struct(save, &tmp, b.mapping)
	mts.Covert(save, &tmp, b.mapping)
	fieldParam := make([]string, 0)
	insertParam := make([]string, 0)
	insertValue := make([]string, 0)
	bindParam := make([]any, 0)
	for k, v := range tmp {
		fieldParam = append(fieldParam, k)
		insertParam = append(insertParam, "?")
		insertValue = append(insertValue, "\""+cast.ToString(v)+"\"")
		bindParam = append(bindParam, v)
	}

	// 日志
	b.logSql = sql
	b.logSql += strings.Join(fieldParam, ",") + ") value(" + strings.Join(insertValue, ",") + ")"
	sql += strings.Join(fieldParam, ",") + ") value(" + strings.Join(insertParam, ",") + ")"
	if b.log {
		return 0, 0
	}
	session := Session(b.SessionId)
	if session.Tx != nil {
		tx := session.Tx
		result, err := tx.Exec(sql, bindParam...)
		lib.ThrowError(err)
		lastInsertId, err = result.LastInsertId()
		lib.ThrowError(err)
		rowsAffect, err = result.RowsAffected()
		lib.ThrowError(err)
		return
	}
	db := b.getDb()
	stmt, err := db.Prepare(sql)
	lib.ThrowError(err)
	defer stmt.Close()
	result, err := stmt.Exec(bindParam...)
	lib.ThrowError(err)
	lastInsertId, err = result.LastInsertId()
	lib.ThrowError(err)
	rowsAffect, err = result.RowsAffected()
	lib.ThrowError(err)
	return
}

// 插入多条数据
func (b *Builder) InsertMany(list []any) (rowsAffect int64, lastInsertId int64) {
	if b.table == nil {
		lib.ThrowError(errors.New(" table is error !"))
	}
	tables := strings.Join(b.table, ",")
	sql := "insert into " + tables + "("
	tmpList := make([]map[string]any, 0)
	for _, val := range list {
		// tmpList = append(tmpList, lib.Map0Struct(val, b.mapping).(map[string]any))
		tmpList = append(tmpList, mts.CovertMap[string, any](val, b.mapping))
	}

	bindParam := make([]any, 0)
	valueArr := make([]string, 0)
	logValueArr := make([]string, 0)
	fieldParam := make([]string, 0)
	for _, val := range tmpList {
		mapInfo := val
		insertParam := make([]string, 0)
		// 用于日志
		insertValue := make([]string, 0)
		if variable.IsEmpty(fieldParam) {
			for k, _ := range mapInfo {
				fieldParam = append(fieldParam, k)
			}
		}
		for _, f := range fieldParam {
			insertValue = append(insertValue, "\""+cast.ToString(mapInfo[f])+"\"")
			insertParam = append(insertParam, "?")
			bindParam = append(bindParam, mapInfo[f])
		}
		valueArr = append(valueArr, "("+strings.Join(insertParam, ",")+")")
		logValueArr = append(logValueArr, "("+strings.Join(insertValue, ",")+")")
	}
	// 日志
	b.logSql = sql
	b.logSql += strings.Join(fieldParam, ",") + ") values" + strings.Join(logValueArr, ",")
	sql += strings.Join(fieldParam, ",") + ") values" + strings.Join(valueArr, ",")
	if b.log {
		return 0, 0
	}
	session := Session(b.SessionId)
	if session.Tx != nil {
		tx := session.Tx
		result, err := tx.Exec(sql, bindParam...)
		lib.ThrowError(err)
		lastInsertId, err = result.LastInsertId()
		lib.ThrowError(err)
		rowsAffect, err = result.RowsAffected()
		lib.ThrowError(err)
		return
	}
	db := b.getDb()
	stmt, err := db.Prepare(sql)
	lib.ThrowError(err)
	defer stmt.Close()
	result, err := stmt.Exec(bindParam...)
	lib.ThrowError(err)
	lastInsertId, err = result.LastInsertId()
	lib.ThrowError(err)
	rowsAffect, err = result.RowsAffected()
	lib.ThrowError(err)
	return
}

func (b *Builder) Update(save any) (rowsAffect int64) {
	tmp := make(map[string]any)
	// lib.Map0Struct(save, &tmp, b.mapping)
	mts.Covert(save, &tmp, b.mapping)
	updateParam := make([]string, 0)
	bpToMap := make(map[string]any)
	for k, v := range tmp {
		bindField := getRealField(k)
		bpToMap[bindField] = v
		if b.log {
			updateParam = append(updateParam, k+"='"+cast.ToString(v)+"'")
		} else {
			updateParam = append(updateParam, k+"= :"+bindField)
		}
	}
	// 表名
	if b.table == nil {
		lib.ThrowError(errors.New(" table is error !"))
	}
	tables := strings.Join(b.table, ",")
	sql := "update " + tables + " set " + strings.Join(updateParam, ",")
	// 条件
	if b.where != nil {
		whereArr := make([]string, 0)
		for _, v := range b.where {
			wstr := v.field + " " + v.operate
			if !b.log && v.bind {
				bindField := getRealField(v.field)
				wstr += " :" + bindField
				bpToMap[bindField] = v.value
			} else {
				if v.value != "" {
					wstr += " '" + v.value + "' "
				}
			}
			whereArr = append(whereArr, wstr)
		}
		sql += " where " + strings.Join(whereArr, " and ")
	}
	b.logSql = sql
	if b.log {
		return 0
	}
	sql, bindParams := sqlBindParam(b, sql, bpToMap)
	session := Session(b.SessionId)

	// fmt.Println("会话id", b.SessionId, session.Tx)
	if session.Tx != nil {
		tx := session.Tx
		result, err := tx.Exec(sql, bindParams...)
		lib.ThrowError(err)
		rowsAffect, err = result.RowsAffected()
		lib.ThrowError(err)
		return
	}
	db := b.getDb()
	stmt, err := db.Prepare(sql)
	lib.ThrowError(err)
	defer stmt.Close()
	result, err := stmt.Exec(bindParams...)
	lib.ThrowError(err)
	rowsAffect, err = result.RowsAffected()
	lib.ThrowError(err)
	return
}

// 删除
func (b *Builder) Delete() (rowsAffect int64) {
	// 表名
	if b.table == nil {
		lib.ThrowError(errors.New(" table is error !"))
	}
	tables := strings.Join(b.table, ",")
	sql := "delete from " + tables
	bpToMap := make(map[string]any)
	// 条件
	if b.where != nil {
		whereArr := make([]string, 0)
		for _, v := range b.where {
			wstr := v.field + " " + v.operate
			if !b.log && v.bind {
				bindField := getRealField(v.field)
				wstr += " :" + bindField
				bpToMap[bindField] = v.value
			} else {
				if v.value != "" {
					wstr += " '" + v.value + "' "
				}
			}
			whereArr = append(whereArr, wstr)
		}
		sql += " where " + strings.Join(whereArr, " and ")
	}
	b.logSql = sql
	if b.log {
		return 0
	}
	sql, bindParams := sqlBindParam(b, sql, bpToMap)
	session := Session(b.SessionId)
	if session.Tx != nil {
		tx := session.Tx
		result, err := tx.Exec(sql, bindParams...)
		lib.ThrowError(err)
		rowsAffect, err = result.RowsAffected()
		lib.ThrowError(err)
		return
	}
	db := b.getDb()
	stmt, err := db.Prepare(sql)
	lib.ThrowError(err)
	defer stmt.Close()
	result, err := stmt.Exec(bindParams...)
	lib.ThrowError(err)
	rowsAffect, err = result.RowsAffected()
	lib.ThrowError(err)
	return
}
